package app.project.streetlensproject.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.Matrix;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Build;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.ImageView;
import app.project.streetlensproject.HomeActivity;
import app.project.streetlensproject.R;
import app.project.streetlensproject.model.Place;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.PolylineOptions;

public class Utilities {

	public static Utilities instance;

	public static Utilities getInstance() {
		if (instance == null) {
			instance = new Utilities();
		}

		return instance;
	}

	/**
	 * get URL with position of source,destination
	 * 
	 * @param sourcelat
	 * @param sourcelog
	 * @param destlat
	 * @param destlog
	 * @param mode
	 * @return
	 */
	public String makeURL(double sourcelat, double sourcelog, double destlat,
			double destlog, String mode) {
		StringBuilder urlString = new StringBuilder();
		urlString.append("http://maps.googleapis.com/maps/api/directions/json");
		urlString.append("?origin=");// from
		urlString.append(Double.toString(sourcelat));
		urlString.append(",");
		urlString.append(Double.toString(sourcelog));
		urlString.append("&destination=");// to
		urlString.append(Double.toString(destlat));
		urlString.append(",");
		urlString.append(Double.toString(destlog));
		urlString.append("&sensor=true&mode=" + mode + "&alternatives=true");
		return urlString.toString();
	}

	/**
	 * draw path with result return
	 * 
	 * @param map
	 * @param result
	 */
	public void drawPath(GoogleMap map, String result) {

		try {
			// Tranform the string into a json object
			final JSONObject json = new JSONObject(result);
			JSONArray routeArray = json.getJSONArray("routes");
			JSONObject routes = routeArray.getJSONObject(0);
			JSONObject overviewPolylines = routes
					.getJSONObject("overview_polyline");
			String encodedString = overviewPolylines.getString("points");
			List<LatLng> list = decodePoly(encodedString);

			for (int z = 0; z < list.size() - 1; z++) {
				LatLng src = list.get(z);
				LatLng dest = list.get(z + 1);
				map.addPolyline(new PolylineOptions()
						.add(new LatLng(src.latitude, src.longitude),
								new LatLng(dest.latitude, dest.longitude))
						.width(5).color(Color.BLUE).geodesic(true));
			}

		} catch (JSONException e) {

		}
	}

	/**
	 * get arraylist of html instruction of route direction
	 * 
	 * @param result
	 * @return
	 */
	public ArrayList<String> getHtmlInstruction(String result) {

		try {
			JSONObject json = new JSONObject(result);
			JSONArray routeArray = json.getJSONArray("routes");
			JSONObject routes = routeArray.getJSONObject(0);
			JSONArray legArray = routes.getJSONArray("legs");
			JSONObject legs = legArray.getJSONObject(0);
			JSONArray steps = legs.getJSONArray("steps");

			ArrayList<String> resultHTMLInsuction = new ArrayList<String>();

			for (int i = 0; i < steps.length(); i++) {
				JSONObject htmlInsuction = steps.getJSONObject(i);
				String instruction = htmlInsuction
						.getString("html_instructions").toString()
						.replaceAll("\n", "").replaceAll("\r", "");
				resultHTMLInsuction.add(instruction);
			}
			return resultHTMLInsuction;
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * read json from url
	 * 
	 * @param url
	 * @return
	 * @throws MalformedURLException
	 * @throws IOException
	 */
	public String readJsonFromUrl(String url) throws MalformedURLException,
			IOException {
		InputStream is = new URL(url).openStream();
		try {
			BufferedReader rd = new BufferedReader(new InputStreamReader(is,
					Charset.forName("UTF-8")));
			String jsonText = readAll(rd);
			JSONObject json = new JSONObject(jsonText);
			return json.toString();
		} catch (IOException e) {
			// TODO: handle exception
			return null;
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		} finally {
			is.close();
		}
	}

	private String readAll(Reader rd) throws IOException {
		StringBuilder sb = new StringBuilder();
		int cp;
		while ((cp = rd.read()) != -1) {
			sb.append((char) cp);
		}
		return sb.toString();
	}

	public BitmapDescriptor getBitmapDescriptionFromType(int type) {
		if (type == Constants.ID_C_ALL) {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_all);
		} else if (type == Constants.ID_C_OTHER) {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_other);
		} else if (type == Constants.ID_C_FOOD) {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_food);
		} else if (type == Constants.ID_C_SHOP) {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_shoping);
		} else if (type == Constants.ID_C_BANK) {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_bank);
		} else if (type == Constants.ID_C_KHAN_CAP) {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_fuel);
		} else if (type == Constants.ID_C_FUEL) {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_fuel);
		} else if (type == Constants.ID_C_GIAI_TRI) {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_hotel);
		} else if (type == Constants.ID_C_HOTEL) {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_hotel);
		} else if (type == Constants.ID_C_BUS) {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_bus);
		} else {
			return BitmapDescriptorFactory.fromResource(R.drawable.ic_school);
		}
	}

	/**
	 * decode street
	 * 
	 * @param encoded
	 * @return
	 */
	private List<LatLng> decodePoly(String encoded) {

		List<LatLng> poly = new ArrayList<LatLng>();
		int index = 0, len = encoded.length();
		int lat = 0, lng = 0;

		while (index < len) {
			int b, shift = 0, result = 0;
			do {
				b = encoded.charAt(index++) - 63;
				result |= (b & 0x1f) << shift;
				shift += 5;
			} while (b >= 0x20);
			int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
			lat += dlat;

			shift = 0;
			result = 0;
			do {
				b = encoded.charAt(index++) - 63;
				result |= (b & 0x1f) << shift;
				shift += 5;
			} while (b >= 0x20);
			int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
			lng += dlng;

			LatLng p = new LatLng((((double) lat / 1E5)),
					(((double) lng / 1E5)));
			poly.add(p);
		}

		return poly;
	}

	/**
	 * get angle between two point with vertical
	 * 
	 * @param place1
	 * @param place2
	 * @return
	 */
	public float getAngleTwoPoint(LatLng place1, LatLng place2) {
		double sourceLat = place1.latitude;
		double sourceLong = place1.longitude;
		double destLat = place2.latitude;
		double destLong = place2.longitude;

		double angle = Math
				.atan2(-(destLong - sourceLong), destLat - sourceLat);
		if (angle < 0) {
			angle += 2 * Math.PI;
		}
		return Float.parseFloat(String.valueOf(angle));
	}

	/**
	 * get lat,lng of current place of user
	 * 
	 * @param context
	 * @return
	 */
	public LatLng getLatLngCurrentUser(Context context) {
		LocationManager lm = (LocationManager) context
				.getSystemService(Context.LOCATION_SERVICE);
		Location location = lm
				.getLastKnownLocation(LocationManager.GPS_PROVIDER);
		double longitude = location.getLongitude();
		double latitude = location.getLatitude();
		return new LatLng(latitude, longitude);
	}

	/**
	 * create circle from place of user
	 * 
	 * @param mMap
	 * @param latitude
	 * @param longitude
	 * @param radius
	 */
	public void drawCircle(GoogleMap mMap, double latitude, double longitude,
			int radius) {
		mMap.addCircle(new CircleOptions()
				.center(new LatLng(latitude, longitude)).radius(radius)
				.strokeColor(Color.GREEN)
				.fillColor(Color.parseColor("#00000000")));
	}

	/**
	 * get angle between two point in google map
	 * 
	 * @return
	 */
	public double getAngleTwoPoint() {
		double lat1 = 21.030814;
		double lat2 = 21.029151;
		double long1 = 105.78602;
		double long2 = 105.782222;
		double deltaLong = long2 - long1;
		double angle = Math.atan2(
				Math.sin(deltaLong) * Math.cos(lat2),
				Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
						* Math.cos(lat2) * Math.cos(deltaLong));
		return Math.toDegrees(angle);
	}

	/**
	 * check input format of edittext
	 * 
	 * @param inputName
	 * @return
	 */
	public boolean checkInputFormat(String inputName) {
		if (inputName.trim().equals("")) {
			return false;
		} else {
			return true;
		}
	}

	// get position of maker with lat,long
	public int getPositionMaker(Double longitude, Double latitude,
			ArrayList<Place> listPlace) {
		int result = 0;
		for (int i = 0; i < listPlace.size(); i++) {
			if (Double.parseDouble(String.valueOf(listPlace.get(i).locationx)) == getDoublePosition(longitude)
					&& Double
							.parseDouble(String.valueOf(listPlace.get(i).locationy)) == getDoublePosition(latitude)) {
				result = i;
			}
		}
		return result;
	}

	// get position marker
	public int getPositionMakerSelect(String title, ArrayList<Place> listPlace) {
		int result = 0;
		for (int i = 0; i < listPlace.size(); i++) {
			if (listPlace.get(i).placename.equals(title)) {
				result = i;
			}
		}
		return result;
	}

	// get 5 number after ,
	public Double getDoublePosition(Double position) {
		DecimalFormat myFormatter = new DecimalFormat("###.######");
		Double result = Double.parseDouble(myFormatter.format(position));
		return result;
	}

	public double CalculationByDistance(LatLng StartP, LatLng EndP) {
		int Radius = 6371;// radius of earth in Km
		int kmInDec;
		double meter;
		int meterInDec;
		double lat1 = StartP.latitude;
		double lat2 = EndP.latitude;
		double lon1 = StartP.longitude;
		double lon2 = EndP.longitude;
		double dLat = Math.toRadians(lat2 - lat1);
		double dLon = Math.toRadians(lon2 - lon1);
		double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
				+ Math.cos(Math.toRadians(lat1))
				* Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2)
				* Math.sin(dLon / 2);
		double c = 2 * Math.asin(Math.sqrt(a));
		double valueResult = Radius * c;
		double km = valueResult / 1;
		DecimalFormat newFormat = new DecimalFormat("####");
		kmInDec = Integer.valueOf(newFormat.format(km));
		meter = valueResult % 1000;
		meterInDec = Integer.valueOf(newFormat.format(meter));
		Log.i("Radius Value", "" + valueResult + "   KM  " + kmInDec
				+ " Meter   " + meterInDec);
		return Radius * c;
	}

	/**
	 * get angle between two point in google map
	 * 
	 * @param paramDouble1
	 * @param paramDouble2
	 * @param paramDouble3
	 * @param paramDouble4
	 * @return
	 */
	public static float GetAngle(double paramDouble1, double paramDouble2,
			double paramDouble3, double paramDouble4) {
		float f = (float) (180.0F * (float) Math.atan2(paramDouble1
				- paramDouble3, Math.cos(0.01745277777777778D * paramDouble1)
				* (paramDouble2 - paramDouble4)) / 3.1415D);
		if (f >= 0.0F)
			return 180.0F - f;
		return -180.0F - f;
	}

	/**
	 * rotate image view
	 * 
	 * @param paramImageView
	 * @param paramFloat
	 */
	public static void RotateImage(ImageView paramImageView, float paramFloat) {
		if (Build.VERSION.SDK_INT < 11) {
			Matrix localMatrix = new Matrix();
			paramImageView.setScaleType(ImageView.ScaleType.MATRIX);
			localMatrix.postRotate(paramFloat, paramImageView.getDrawable()
					.getBounds().width() / 2, paramImageView.getDrawable()
					.getBounds().height() / 2);
			paramImageView.setImageMatrix(localMatrix);
			return;
		}
		paramImageView.setRotation(paramFloat);
	}

	public LatLng getMyPlace(Context context) {
		double latitude = 0;
		double longitude = 0;
		GPSTracker gps = new GPSTracker(context);
		if (gps.canGetLocation()) {
			latitude = gps.getLatitude();
			longitude = gps.getLongitude();
		} else {
			// default if not get GPS or GPS disable
			latitude = Constants.MYPLACE_DEFAULT.latitude;
			longitude = Constants.MYPLACE_DEFAULT.longitude;
		}
		return new LatLng(latitude, longitude);
	}

	/**
	 * set position of current user to preference
	 */
	public void setMyPlacePreference(Context context) {
		double latitude = 0;
		double longitude = 0;
		GPSTracker gps = new GPSTracker(context);
		if (gps.canGetLocation()) {
			latitude = gps.getLatitude();
			longitude = gps.getLongitude();
		} else {
			// default if not get GPS or GPS disable
			latitude = Constants.MYPLACE_DEFAULT.latitude;
			longitude = Constants.MYPLACE_DEFAULT.longitude;
		}
		// Get the app's shared preferences
		SharedPreferences myPlacePreference = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = myPlacePreference.edit();
		editor.putString("myLatitude", String.valueOf(latitude));
		editor.putString("myLongitude", String.valueOf(longitude));
		editor.commit();
	}

	/**
	 * get lat,long of current user from preference
	 * 
	 * @param context
	 * @return
	 */
	public LatLng getMyPlacePreference(Context context) {
		SharedPreferences sharedPreferences = PreferenceManager
				.getDefaultSharedPreferences(context);
		double latitude = Double.parseDouble(sharedPreferences.getString(
				"myLatitude", "0"));
		double longitude = Double.parseDouble(sharedPreferences.getString(
				"myLongitude", "0"));
		return new LatLng(latitude, longitude);
	}

	/**
	 * get string from image path
	 * 
	 * @param pathName
	 * @return
	 * @throws FileNotFoundException
	 */
	public String getStringBase64FromImage(String pathName)
			throws FileNotFoundException {
		InputStream inputStream = new FileInputStream(pathName);
		byte[] bytes;
		byte[] buffer = new byte[8192];
		int bytesRead;
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		try {
			while ((bytesRead = inputStream.read(buffer)) != -1) {
				output.write(buffer, 0, bytesRead);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		bytes = output.toByteArray();
		String encodedString = android.util.Base64.encodeToString(bytes,
				android.util.Base64.DEFAULT);
		return encodedString;
	}

	// helper function to check if Maps is installed
	public boolean isAppInstalled(String uri, Context context) {
		PackageManager pm = context.getApplicationContext().getPackageManager();
		boolean app_installed = false;
		try {
			pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
			app_installed = true;
		} catch (PackageManager.NameNotFoundException e) {
			app_installed = false;
		}
		return app_installed;
	}

	public void gotoGoogleMap(Context context, LatLng dPlace, String mode) {

		Intent localIntent = new Intent("android.intent.action.VIEW",
				Uri.parse("http://maps.google.com/maps?saddr="
						+ HomeActivity.MY_LATITUDE + ","
						+ HomeActivity.MY_LONGITUDE + "&daddr="
						+ dPlace.latitude + "," + dPlace.longitude
						+ "&&dirflg=" + mode));
		localIntent.setClassName("com.google.android.apps.maps",
				"com.google.android.maps.MapsActivity");
		context.startActivity(localIntent);

	}

	public ArrayList<Place> getPlaceInAngle(Context context,
			ArrayList<Place> listPlace, float angleRoll) {
		float minAngle = 0F;
		float maxAngle = 90F;
		ArrayList<Place> arrPlace = new ArrayList<Place>();
		for (int i = 0; i < listPlace.size(); i++) {
			Log.e("UpdateAngleRotate:", listPlace.get(i).updateAngleRotate()
					+ "");
			if ((listPlace.get(i).updateAngleRotate() + angleRoll) >= minAngle
					&& listPlace.get(i).updateAngleRotate() + angleRoll <= maxAngle
					|| listPlace.get(i).updateAngleRotate() + angleRoll <= minAngle
					&& listPlace.get(i).updateAngleRotate() + angleRoll >= -maxAngle) {
				arrPlace.add(listPlace.get(i));
			}
		}
		return arrPlace;
	}

	public void callMobilePlace(Context context, String mobile) {
		Intent intent = new Intent(Intent.ACTION_DIAL);
		intent.setData(Uri.parse("tel:" + mobile));
		context.startActivity(intent);
	}

	public String getVideoID(String url, int type) {
		int ind1 = url.indexOf("v=");
		int ind2 = url.indexOf("&");
		int ind3 = url.length();
		String id = "";
		if (type == 0) {
			id = url.substring(ind1 + 2, ind2);
		} else {
			id = url.substring(ind1 + 2, ind3);
		}
		return id;
	}

	public void watchYoutubeVideo(String id, Context context) {
		try {
			Intent intent = new Intent(Intent.ACTION_VIEW,
					Uri.parse("vnd.youtube:" + id));
			context.startActivity(intent);
		} catch (ActivityNotFoundException ex) {
			Intent intent = new Intent(Intent.ACTION_VIEW,
					Uri.parse("http://www.youtube.com/watch?v=" + id));
			context.startActivity(intent);
		}
	}

	public void openWeb(Context context, String url) {
		Uri uriUrl = Uri.parse(url);
		Intent launchBrowser = new Intent(Intent.ACTION_VIEW, uriUrl);
		context.startActivity(launchBrowser);
	}

	/**
	 * share by mail
	 * 
	 * @param mContext
	 */
	public void sendMail(Context mContext, String email) {
		Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("mailto:"
				+ email));
		intent.putExtra(Intent.EXTRA_SUBJECT, "Thắc mắc,góp ý");
		intent.putExtra(Intent.EXTRA_TEXT, "Text");
		mContext.startActivity(intent);
	}

	public String getValueByType(int type, String description) {
		String result = "---";
		if (description.contains("*")) {
			String[] values = description.split("\\*");

			if (type == Constants.TYPE_INFO) {
				for (int i = 0; i < values.length; i++) {
					if (values[i].contains("Info")) {
						int index = values[i].indexOf(":");
						int indexLast = values[i].length();
						result = values[i].substring(index + 1, indexLast);
					}
				}
			}

			if (type == Constants.TYPE_ADDRESS) {
				for (int i = 0; i < values.length; i++) {
					if (values[i].contains("Address")) {
						int index = values[i].indexOf(":");
						int indexLast = values[i].length();
						result = values[i].substring(index + 1, indexLast);
					}
				}
			}

			if (type == Constants.TYPE_MOBILE) {
				for (int i = 0; i < values.length; i++) {
					if (values[i].contains("Phone")) {
						int index = values[i].indexOf(":");
						int indexLast = values[i].length();
						result = values[i].substring(index + 1, indexLast);
					}
				}
			}

			if (type == Constants.TYPE_MOBILE_PHONE) {
				for (int i = 0; i < values.length; i++) {
					if (values[i].contains("MobilePhone")) {
						int index = values[i].indexOf(":");
						int indexLast = values[i].length();
						result = values[i].substring(index + 1, indexLast);
					}
				}
			}

			if (type == Constants.TYPE_FAX) {
				for (int i = 0; i < values.length; i++) {
					if (values[i].contains("Fax")) {
						int index = values[i].indexOf(":");
						int indexLast = values[i].length();
						result = values[i].substring(index + 1, indexLast);
					}
				}
			}

			if (type == Constants.TYPE_VIDEO) {
				for (int i = 0; i < values.length; i++) {
					if (values[i].contains("Video")) {
						int index = values[i].indexOf(":");
						int indexLast = values[i].length();
						result = values[i].substring(index + 1, indexLast);
					}
				}
			}

			if (type == Constants.TYPE_WEBSITE) {
				for (int i = 0; i < values.length; i++) {
					if (values[i].contains("Website")) {
						int index = values[i].indexOf(":");
						int indexLast = values[i].length();
						result = values[i].substring(index + 1, indexLast);
					}
				}
			}

			if (type == Constants.TYPE_EMAIL) {
				for (int i = 0; i < values.length; i++) {
					if (values[i].contains("Email")) {
						int index = values[i].indexOf(":");
						int indexLast = values[i].length();
						result = values[i].substring(index + 1, indexLast);
					}
				}
			}
		}
		return result;
	}

	/**
	 * get description from all edit
	 * 
	 * @param infor
	 * @param address
	 * @param mobile
	 * @param mobilephone
	 * @param fax
	 * @param video
	 * @param website
	 * @param email
	 * @return
	 */
	public String getDescriptionValue(String infor, String address,
			String mobile, String mobilephone, String fax, String video,
			String website, String email) {
		String result = "";
		if (!infor.trim().equals("")) {
			result += "Info:" + infor;
		}
		if (!address.trim().equals("")) {
			result += "*Address:" + address;
		}
		if (!mobile.trim().equals("")) {
			result += "*Phone:" + mobile;
		}
		if (!mobilephone.trim().equals("")) {
			result += "*MobilePhone:" + mobilephone;
		}
		if (!fax.trim().equals("")) {
			result += "*Fax:" + fax;
		}
		if (!video.trim().equals("")) {
			result += "*Video:" + video;
		}
		if (!website.trim().equals("")) {
			result += "*Website:" + website;
		}
		if (!email.trim().equals("")) {
			result += "*Email:" + email;
		}
		return result;
	}

	/**get value of category with type language
	 * @param category
	 * @param language
	 * @return
	 */
	public ArrayList<String> getValueCategory(ArrayList<String> category,
			int language) {
		ArrayList<String> arrResult = new ArrayList<String>();
		for (int i = 0; i < category.size(); i++) {
			String val = category.get(i);
			int index = val.indexOf("*");
			String valVN = val.substring(0, index);
			String valEN = val.substring(index + 1, val.length());
			if (language == Constants.LANGUAGE_VN) {
				arrResult.add(valVN);
			} else {
				arrResult.add(valEN);
			}
		}
		return arrResult;
	}

}
